﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using XCI.Data.Entity;

namespace XCI.Data.Provider
{
    /// <summary>
    /// SQLServer数据库实现
    /// </summary>
    public class SQLServerProvider : BaseProvider
    {
        public SQLServerProvider()
        {

        }

        /// <summary>
        /// 获取数据对象创建工厂
        /// </summary>
        /// <returns></returns>
        public override DbProviderFactory GetDbProviderFactory()
        {
            return SqlClientFactory.Instance;
        }

        /// <summary>
        /// 获取参数前缀
        /// </summary>
        public override string GetParamPrefix()
        {
            return "@";
        }

        /// <summary>
        /// 获取Insert语句模板
        /// </summary>
        /// <param name="entityData">实体信息</param>
        /// <param name="cmd">Insert命令对象</param>
        public override void PrepInsert(EntityData entityData, DbCommand cmd)
        {
            if (entityData.PrimaryAttr == null || !entityData.PrimaryAttr.Auto) return;

            string sql = cmd.CommandText;
            int index = sql.IndexOf("values", StringComparison.OrdinalIgnoreCase);
            cmd.CommandText = sql.Insert(index, $" output inserted.{entityData.PrimaryProperty.DbName} ");
        }

        /// <summary>
        /// 获取分页语句模板
        /// </summary>
        /// <param name="sql">查询语句</param>
        /// <param name="orderBy"></param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        /// <returns>获取分页语句模板</returns>
        public override string GetPageStatement(string sql, string orderBy, int startIndex, int endIndex)
        {
            return $"with grid as (select *,row_number() over ({orderBy}) rownum from ({sql}) x ) select * from grid where rownum between {startIndex} and {endIndex}";
        }

        /// <summary>
        /// Builds an SQL query suitable for performing page based queries to the database
        /// </summary>
        /// <param name="skip">The number of rows that should be skipped by the query</param>
        /// <param name="take">The number of rows that should be retruend by the query</param>
        /// <param name="parts">The original SQL query after being parsed into it's component parts</param>
        /// <returns>The final SQL query that should be executed.</returns>
        public override string BuildPageQuery(long skip, long take, PagingHelper.SQLParts parts)
        {
            parts.sqlSelectRemoved = PagingHelper.rxOrderBy.Replace(parts.sqlSelectRemoved, "", 1);
            if (PagingHelper.rxDistinct.IsMatch(parts.sqlSelectRemoved))
            {
                parts.sqlSelectRemoved = "peta_inner.* FROM (SELECT " + parts.sqlSelectRemoved + ") peta_inner";
            }
            var sqlPage =
                $"SELECT * FROM (SELECT ROW_NUMBER() OVER ({(parts.sqlOrderBy == null ? "ORDER BY (SELECT NULL)" : parts.sqlOrderBy)}) peta_rn, {parts.sqlSelectRemoved}) peta_paged WHERE peta_rn>{skip} AND peta_rn<={skip + take}";

            return sqlPage;
        }
    }
}